package com.xs.mcpserver.gitlab;

import com.xs.mcpserver.config.GitLabApiHolder;
import com.xs.mcpserver.gitlab.model.*;
import lombok.extern.slf4j.Slf4j;
import org.gitlab4j.api.DiscussionsApi;
import org.gitlab4j.api.GitLabApi;
import org.gitlab4j.api.GitLabApiException;
import org.gitlab4j.api.MergeRequestApi;
import org.gitlab4j.api.models.*;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * GitLab代码审查服务
 * 提供与GitLab交互的功能，包括获取MR信息、获取变更内容、提交评论等
 */
@Slf4j
@Service
public class GitLabReviewService {


    private final CodeAnalysisService codeAnalysisService;

    public GitLabReviewService(CodeAnalysisService codeAnalysisService) {
        this.codeAnalysisService = codeAnalysisService;
    }

    /**
     * 获取MR信息
     */
    @Tool(description = "获取MR信息(get_merge_request_info)")
    public MergeRequestInfo getMergeRequestInfo(
            @ToolParam(description = "GitLab项目ID或路径") String projectId,
            @ToolParam(description = "合并请求IID") Long mergeRequestIid) {

        try {
            GitLabApi gitLabApi = getGitLabApi();
            MergeRequestApi mrApi = gitLabApi.getMergeRequestApi();
            MergeRequest mr = mrApi.getMergeRequest(projectId, mergeRequestIid);

            return new MergeRequestInfo(
                    mr.getIid(),
                    mr.getTitle(),
                    mr.getDescription(),
                    mr.getSourceBranch(),
                    mr.getTargetBranch(),
                    mr.getAuthor().getName(),
                    mr.getCreatedAt(),
                    mr.getWebUrl()
            );
        } catch (GitLabApiException e) {
            throw new RuntimeException("获取合并请求信息失败: " + e.getMessage(), e);
        }
    }

    /**
     * 获取MR中的变更文件列表
     */
    @Tool(description = "获取MR中的变更文件列表(get_merge_request_changes)")
    public MergeRequestChanges getMergeRequestChanges(
            @ToolParam(description = "GitLab项目ID或路径") String projectId,
            @ToolParam(description = "合并请求IID") Long mergeRequestIid) {

        try {
            GitLabApi gitLabApi = getGitLabApi();
            List<Diff> diffs = gitLabApi.getMergeRequestApi().getMergeRequestChanges(projectId, mergeRequestIid).getChanges();

            List<FileChange> fileChanges = diffs.stream()
                    .map(diff -> new FileChange(
                            diff.getNewPath(),
                            diff.getOldPath(),
                            diff.getNewFile(),
                            diff.getRenamedFile(),
                            diff.getDeletedFile()
                    ))
                    .collect(Collectors.toList());

            return new MergeRequestChanges(fileChanges);
        } catch (GitLabApiException e) {
            throw new RuntimeException("获取合并请求变更失败: " + e.getMessage(), e);
        }
    }

    /**
     * 获取单个文件的变更内容
     */
    @Tool(description = "获取单个文件的变更内容(get_file_diff)")
    public FileDiffContent getFileDiff(
            @ToolParam(description = "GitLab项目ID或路径") String projectId,
            @ToolParam(description = "合并请求IID") Long mergeRequestIid,
            @ToolParam(description = "文件路径") String filePath) {

        try {
            GitLabApi gitLabApi = getGitLabApi();
            List<Diff> diffs = gitLabApi.getMergeRequestApi().getMergeRequestChanges(projectId, mergeRequestIid).getChanges();

            Optional<Diff> fileDiff = diffs.stream()
                    .filter(diff -> diff.getNewPath().equals(filePath) || diff.getOldPath().equals(filePath))
                    .findFirst();

            if (fileDiff.isPresent()) {
                Diff diff = fileDiff.get();

                // 获取文件的完整内容以提供上下文
                String fileContent = "";
                try {
                    if (!diff.getDeletedFile()) {
                        fileContent = gitLabApi.getRepositoryFileApi().getFile(
                                projectId, diff.getNewPath(), gitLabApi.getMergeRequestApi().getMergeRequest(projectId, mergeRequestIid).getSourceBranch()
                        ).getDecodedContentAsString();
                    }
                } catch (Exception e) {
                    // 如果无法获取完整文件内容，继续使用差异
                    log.warn("无法获取文件完整内容，使用差异作为上下文:", e);
                }

                // 使用代码分析服务分析上下文
                Map<String, String> contextInfo = codeAnalysisService.analyzeCodeContext(fileContent, diff.getDiff());

                return new FileDiffContent(
                        diff.getNewPath(),
                        diff.getOldPath(),
                        diff.getDiff(),
                        fileContent,
                        contextInfo
                );
            } else {
                throw new RuntimeException("在合并请求中未找到指定文件: " + filePath);
            }
        } catch (GitLabApiException e) {
            throw new RuntimeException("获取文件差异失败: " + e.getMessage(), e);
        }
    }

    /**
     * 添加代码行评论
     */
    @Tool(description = "添加代码行评论(add_line_comment)")
    public CommentResult addLineComment(
            @ToolParam(description = "GitLab项目ID或路径") String projectId,
            @ToolParam(description = "合并请求IID") Long mergeRequestIid,
            @ToolParam(description = "文件路径") String filePath,
            @ToolParam(description = "新文件中的行号") Integer newLine,
            @ToolParam(description = "旧文件中的行号，如果是新增行则为null") Integer oldLine,
            @ToolParam(description = "评论内容") String comment) {

        try {
            GitLabApi gitLabApi = getGitLabApi();
            MergeRequestApi mrApi = gitLabApi.getMergeRequestApi();
            MergeRequest mr = mrApi.getMergeRequest(projectId, mergeRequestIid);

            Position position = new Position();
            position.setBaseSha(mr.getDiffRefs().getBaseSha());
            position.setHeadSha(mr.getDiffRefs().getHeadSha());
            position.setStartSha(mr.getDiffRefs().getStartSha());
            position.setPositionType(Position.PositionType.TEXT);
            position.setNewPath(filePath);
            position.setOldPath(filePath);
            position.setNewLine(newLine);
            position.setOldLine(oldLine);

            // 使用DiscussionsApi创建讨论
            DiscussionsApi discussionsApi = gitLabApi.getDiscussionsApi();

            // 使用正确的参数调用createMergeRequestDiscussion方法
            Discussion discussion = discussionsApi.createMergeRequestDiscussion(
                    projectId,        // projectIdOrPath
                    mergeRequestIid,  // mergeRequestIid
                    comment,         // body (评论内容)
                    null,           // createdAt (使用默认时间)
                    null,           // positionHash (不需要)
                    position        // position (位置信息)
            );
            Note note = discussion.getNotes().get(0);

            return new CommentResult(note.getId(), note.getBody(), filePath, newLine, true);
        } catch (GitLabApiException e) {
            return new CommentResult(null, comment, filePath, newLine, false, "添加评论失败: " + e.getMessage());
        }
    }

    /**
     * 添加MR总结评论
     */
    @Tool(description = "添加MR总结评论(add_summary_comment)")
    public CommentResult addSummaryComment(
            @ToolParam(description = "GitLab项目ID或路径") String projectId,
            @ToolParam(description = "合并请求IID") Long mergeRequestIid,
            @ToolParam(description = "总结内容") String summary) {

        try {
            GitLabApi gitLabApi = getGitLabApi();
            Note note = gitLabApi.getNotesApi().createMergeRequestNote(projectId, mergeRequestIid, summary,
                    null, // createdAt: 使用服务器时间
                    null  // internal: 不设置是否为内部评论
            );
            return new CommentResult(note.getId(), note.getBody(), null, null, true);
        } catch (GitLabApiException e) {
            return new CommentResult(null, summary, null, null, false, "添加总结评论失败: " + e.getMessage());
        }
    }

    /**
     * 获取GitLab API客户端
     */
    private GitLabApi getGitLabApi() {
        return GitLabApiHolder.getGitLabApi();
    }

}
